﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Windows.Forms;

namespace Clustering_IA_Project
{
    /// <summary>
    /// Le word formattate per essere scritte dal parser su xml
    /// </summary>
    public class WordXML: System.Object
    {
        public String word;
        public String webPage;
        public String user;
        public int numPageWord;
        public int fixNumb;
        public float fixTime;
        public float idf;
        public List<String> context;
        public List<float> contextFixTime;
        public float tfcMeans;

        /// <summary>
        /// Confronta se due wordXML hanno stessa termine e contesto
        /// </summary>
        /// <param name="w">la wordXml da confrontare</param>
        /// <returns></returns>
        public bool equals(WordXML w)
        {
            if (this.word == w.word && this.context.Count == w.context.Count)
            {
                for (int i = 0; i < this.context.Count; i++)
                {
                    if (this.context[i] != w.context[i])
                        return false;
                }
                return true;
            }
            return false;
        }


        public override bool Equals(System.Object obj)
        {
            if (obj == null)
            {
                return false;
            }
            WordXML wx = (WordXML) obj;
            if (this.word == wx.word && this.webPage == wx.webPage && this.context.Count == wx.context.Count)
            {
                for (int i = 0; i < this.context.Count; i++)
                {
                    if (this.context[i] != wx.context[i])
                        return false;
                }
                return true;
            }
            return false;
        }

        public bool Equals(WordXML w)
        {
            if ((object)w == null)
            {
                return false;
            }
            WordXML wx = w;
            if (this.word == wx.word && this.webPage == wx.webPage && this.context.Count == wx.context.Count)
            {
                for (int i = 0; i < this.context.Count; i++)
                {
                    if (this.context[i] != wx.context[i])
                        return false;
                }
                return true;
            }
            return false; 
        }

        public override int GetHashCode()
        {
            MD5 md5 = MD5.Create();
            string input = this.word + this.webPage + this.context.Count.ToString();
            foreach (string s in this.context){ input += s; }
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hash = md5.ComputeHash(inputBytes);
            //StringBuilder sb = new StringBuilder();
            //for (int i = 0; i < hash.Length; i++)
            //{
              //  sb.Append(hash[i].ToString("X2"));
            //}
            //return BitConverter.ToInt32(new MD5CryptoServiceProvider().ComputeHash(inputBytes), 0);
            return BitConverter.ToInt32(hash, 0); 
        }
    }

    /// <summary>
    /// Classe che legge gli Xml e aggiunge il loro contenuto alla lista passata
    /// nel costruttore
    /// </summary>
    class XmlReader
    {
        List<WordXML> listWord = new List<WordXML>();
        WordXML wordF;
        int[] num_array, num_totWord;
        int counter;
        List<string> file;

        /// <summary>
        /// Prendo in ingresso la pagina devo leggere e la cerco tra i file xlm
        /// </summary>
        /// <param name="pageName">il nome della pagina da caricare</param>
        private void ReadXML(String pageName)
        {
            //leggo il file XLM
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(pageName);


            XmlNodeList lwebPage = xmlDoc.GetElementsByTagName("webpage");

            num_totWord = new int[lwebPage.Count];
            for (int t = 0; t < lwebPage.Count; t++)
            {
                num_totWord[t] = int.Parse(lwebPage[t].Attributes["lenght"].Value.Trim());
            }

            XmlNodeList luser = xmlDoc.GetElementsByTagName("user");
            XmlNodeList lword = xmlDoc.GetElementsByTagName("wname");
            XmlNodeList lfixNumb = xmlDoc.GetElementsByTagName("number_fixations");
            XmlNodeList lfixTime = xmlDoc.GetElementsByTagName("time_fixations");
            XmlNodeList lidf = xmlDoc.GetElementsByTagName("idf");
            XmlNodeList lcontext = xmlDoc.GetElementsByTagName("context");

            num_array = new int[lcontext.Count];
            for (int i = 0; i < lcontext.Count; i++)
            {
                num_array[i] = int.Parse(lcontext[i].Attributes["terms"].Value.Trim());
            }

            XmlNodeList lterm = xmlDoc.GetElementsByTagName("term");
            XmlNodeList lcontextTime = xmlDoc.GetElementsByTagName("time");
            XmlNodeList ltfcMeans = xmlDoc.GetElementsByTagName("tfc_mean");

            counter = 0;
            //carico le word nella lista listWord
            for (int j = 0; j < lword.Count; j++)
            {
                int app = 0;
                wordF = new WordXML();
                wordF.context = new List<String>();
                wordF.contextFixTime = new List<float>();

                wordF.word = lword[j].InnerText.Trim();
                wordF.webPage = lwebPage[j].InnerText.Trim();
                wordF.user = luser[j].InnerText.Trim();
                wordF.numPageWord = num_totWord[j];
                wordF.fixNumb = int.Parse(lfixNumb[j].InnerText.Trim());
                wordF.fixTime = float.Parse(lfixTime[j].InnerText.Trim());
                wordF.idf = float.Parse(lidf[j].InnerText.Trim());

                //prelevo tanti term e tanti time quanti ne ha la parola
                for (int k = 0; k < num_array[j]; k++)
                {
                    wordF.context.Add(lterm[j + k + counter].InnerText.Trim());
                    wordF.contextFixTime.Add(float.Parse(lcontextTime[j + k + counter].InnerText.Trim()));
                    app++;
                }

                //metto in counter quanti term ho preso meno lo scarto dovuto all'ultimo ciclo for
                counter = counter + app - 1;

                wordF.tfcMeans = float.Parse(ltfcMeans[j].InnerText.Trim());
                listWord.Add(wordF);
            }
        }

        /// <summary>
        /// metodo che legge tutti i file della directoy indicata, poi ne carica il contenuto 
        /// in una lista e la restituisce
        /// </summary>
        /// <param name="path">path della directory da ispezionare</param>
        /// <returns></returns>
        public List<WordXML> read(List<string> f)
        {
            file = f;
            foreach (string nameFile in file)
            {
                ReadXML(nameFile);
            }
            //stampa();
            return listWord;
        }
    }
}
